home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #2 / Amiga Plus CD - 2004 - No. 02.iso / AmigaPlus / Tools / Virus / CheckX / sources / SortCheckX.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-11-27  |  21.9 KB  |  701 lines

  1. #define NAME         "SortCheckX"
  2. #define REVISION     "5"
  3. #define DISTRIBUTION "(Freeware) "
  4. #define DATE         "09.03.2003"
  5. #define VERSION      "1"
  6. #define AUTHOR       "by Dirk Stöcker <stoecker@epost.de>"
  7.  
  8. /* Programmheader
  9.  
  10.         Name:           SortCheckX
  11.         Author:         SDI
  12.         Distribution:   PD
  13.         Description:    sorts CheckX output by file name to make comparisons possibly
  14.         Compileropts:   -
  15.         Linkeropts:     -gsi
  16.  
  17.  1.0   14.08.02 : first version
  18.  1.1   15.08.02 : added OLDFIX, CRC and OUTFILE
  19.  1.2   16.08.02 : added buffered Output, optimized
  20.  1.3   17.08.02 : added secondary filesystem support
  21.  1.4   01.01.03 : fixed bug with short buffer allocations due to counting
  22.     error in case of disk images and filesystems
  23.  1.5   09.03.03 : added more texts, changed build process
  24. */
  25.  
  26. #include <proto/dos.h>
  27. #include <proto/exec.h>
  28. #include <exec/memory.h>
  29.  
  30. #define version "$VER: " NAME " " VERSION "." REVISION " (" DATE ") " DISTRIBUTION AUTHOR
  31. #define PARAM           "INFILE/A,OUTFILE,OLDFIX/S,CRC/S"
  32.  
  33. struct Args {
  34.   STRPTR infile;
  35.   STRPTR outfile;
  36.   ULONG  oldfix; /* tries to reduce the differences by fixing older texts */
  37.   ULONG  crc;
  38. };
  39.  
  40. struct CNode {
  41.   struct CNode *Prev;
  42.   struct CNode *Next;
  43.   struct CNode *Sub;
  44.   struct CNode *Head;
  45.   ULONG         BufferPos; /* invalid after Sorting head structure */
  46.   ULONG         Size;
  47.   UWORD         Flags;
  48. };
  49.  
  50. #define FLAG_DISKIMAGE  (1<<0)
  51. #define FLAG_INFOTEXT   (1<<1)
  52. #define FLAG_UNUSED     (1<<2)
  53. #define FLAG_CRC        (1<<3)
  54. #define FLAG_FILESYSTEM (1<<4)
  55.  
  56. #define OUTBUFSIZE 16384
  57.  
  58. struct MyOutBuf {
  59.   ULONG              CurSize;
  60.   struct ExecBase   *SysBase;
  61.   struct DosLibrary *DOSBase;
  62.   BPTR               FileHandle;
  63.   UBYTE              Buffer[OUTBUFSIZE];
  64. };
  65.  
  66. struct MyReplace {
  67.   WORD  Offset;
  68.   UBYTE OldSize;
  69.   UBYTE NewSize;
  70. };
  71.  
  72. /* This is a string field of replace strings:
  73. First comes old, second the new string. Each ends with a '\n'.
  74. The ReplaceField[] structure below contains offset and element sizes of this
  75. string field.
  76.  
  77. Why? Because as result SortCheckX has no Relocs and is very short ;-)
  78. */
  79.  
  80. static const UBYTE StringField[] = {
  81. "CheckX-Error 12: file is empty\n"
  82. "CheckX-Warning 4: file is empty\n"
  83.  
  84. "CheckX-Error 4: read or write failed\n"
  85. "CheckX-Error 4: reading failed\n"
  86.  
  87. "CheckX-Error 100: not enough memory\n"
  88. "CheckX-Error 12: not enough memory for full tests\n"
  89.  
  90. "CheckX-Error 113: could not check for virus\n"
  91. "CheckX-Error 11: could not check for virus\n"
  92.  
  93. "CheckX-Error 106: read or write failed\n"
  94. "CheckX-Error 4: reading failed\n"
  95.  
  96. "DMS-Archive\n"
  97. "DMS (ARCHIVE)\n"
  98.  
  99. "LhA-Archive\n"
  100. "LhA (ARCHIVE)\n"
  101.  
  102. "LhA-SFX-Archive\n"
  103. "LhA SFX (ARCHIVE)\n"
  104.  
  105. "LhA-SFX (ARCHIVE)\n"
  106. "LhA SFX (ARCHIVE)\n"
  107.  
  108. "LzX-Archive\n"
  109. "LZX (ARCHIVE)\n"
  110.  
  111. "Zip-Archive\n"
  112. "Zip (ARCHIVE)\n"
  113.  
  114. "ZOO-Archive\n"
  115. "Zoo (ARCHIVE)\n"
  116.  
  117. "ZOO (ARCHIVE)\n"
  118. "Zoo (ARCHIVE)\n"
  119.  
  120. "Amiga Standard FS (DISKIMAGE)\n"
  121. "Amiga Standard FS (FILESYSTEM)\n"
  122.  
  123. "TSM! Cruncher\n"
  124. "Pack-Ice 2.11 Data\n"
  125.  
  126. "UNIX Compress\n"
  127. "Compress (ARCHIVE)\n"
  128.  
  129. "Lothar Becks Data Cruncher\n"
  130. "LOB's FILE-COMPRESSOR v3.70\n"
  131.  
  132. "(FUCK) Data Cruncher\n"
  133. "Exploder Style Data File\n"
  134. };
  135.  
  136. #ifdef MAKEREPLACEFIELD /* in caseone is to lazy to count by hand ;-) */
  137. const UBYTE *teststr="static const struct MyReplace ReplaceField";
  138. void main(void)
  139. {
  140.   LONG i, n, j, last = -1;
  141.   UBYTE line[300];
  142.   BPTR in, out;
  143.  
  144.   in = Input();
  145.   out = Output();
  146.   n = 0;
  147.   while((i = FGetC(in)) != -1)
  148.   {
  149.     line[n++] = i;
  150.     if(i == '\n')
  151.     {
  152.       line[n] = 0;
  153.       Printf("%s", line);
  154.       for(j = 0; teststr[j] && line[j] == teststr[j]; ++j)
  155.         ;
  156.       if(!teststr[j])
  157.         break;
  158.       n = 0;
  159.     }
  160.   }
  161.  
  162.   i = n = 0;
  163.   do
  164.   {
  165.     if(StringField[i] == '\n')
  166.     {
  167.       if(n++ & 1)
  168.         Printf(/*{*/" %2ld},\n", i-last);
  169.       else
  170.         Printf("{ %3ld, %2ld,"/*}*/, last+1, i-last);
  171.       last = i;
  172.     }
  173.   } while(StringField[++i]);
  174.   Printf("{   0,  0,  0}\n");
  175.  
  176.   n = 0;
  177.   /* skip the old contents */
  178.   while((i = FGetC(in)) != -1)
  179.   {
  180.     line[n++] = i;
  181.     if(i == '\n')
  182.     {
  183.       line[n] = 0;
  184.       if(line[0] != '{'/*»*/)
  185.       {
  186.         Printf("%s", line);
  187.         break;
  188.       }
  189.       n = 0;
  190.     }
  191.   }
  192.  
  193.   while((i = FGetC(in)) != -1)
  194.     FPutC(out, i);
  195. }
  196. #else
  197. static const struct MyReplace ReplaceField[] = {
  198. {   0, 31, 32},
  199. {  63, 37, 31},
  200. { 131, 36, 50},
  201. { 217, 44, 43},
  202. { 304, 39, 31},
  203. { 374, 12, 14},
  204. { 400, 12, 14},
  205. { 426, 16, 18},
  206. { 460, 18, 18},
  207. { 496, 12, 14},
  208. { 522, 12, 14},
  209. { 548, 12, 14},
  210. { 574, 14, 14},
  211. { 602, 30, 31},
  212. { 663, 14, 19},
  213. { 696, 14, 19},
  214. { 729, 27, 28},
  215. { 784, 21, 25},
  216. {   0,  0,  0}
  217. };
  218.  
  219. static LONG mystrncmp(STRPTR a, STRPTR b, ULONG s);
  220. static void SortSubTree(struct CNode *curnode, STRPTR mem, struct ExecBase *SysBase);
  221. static void MyOutput(STRPTR mem, ULONG size, struct MyOutBuf *outbuf);
  222.  
  223. ULONG start(void)
  224. {
  225.   struct DosLibrary *DOSBase;
  226.   struct ExecBase *SysBase = (*((struct ExecBase **) 4));
  227.  
  228.   { /* test for WB and reply startup-message */
  229.     struct Process *task;
  230.     if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  231.     {
  232.       WaitPort(&task->pr_MsgPort);
  233.       Forbid();
  234.       ReplyMsg(GetMsg(&task->pr_MsgPort));
  235.       return RETURN_FAIL;
  236.     }
  237.   }
  238.  
  239.   if((DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  240.   {
  241.     struct Args args;
  242.     struct RDArgs *rda;
  243.  
  244.     args.oldfix = args.crc = 0;
  245.     args.outfile = 0;
  246.     if((rda = ReadArgs(PARAM, (LONG *) &args, 0)))
  247.     {
  248.       BPTR fh;
  249.       if(args.crc)
  250.         args.crc = FLAG_CRC;
  251.       if((fh = Open(args.infile, MODE_OLDFILE)))
  252.       {
  253.         struct FileInfoBlock *fib;
  254.  
  255.         if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
  256.         {
  257.           if(ExamineFH(fh, fib))
  258.           {
  259.             STRPTR mem = version; /* removed by optimizer */
  260.             if((mem = (STRPTR) AllocMem(fib->fib_Size+1, 0)))
  261.             {
  262.               mem[fib->fib_Size] = '\n';
  263.               if(Read(fh, mem, fib->fib_Size) == fib->fib_Size)
  264.               {
  265.                 /* This does no error checking and will produce total crap
  266.                    with non-CheckX files, but should make no crash or other
  267.                    dangerous error. */
  268.                 ULONG i, depth1 = 0, depth2;
  269.                 /* depth 1 --> number of '*', depth2 --> number of - types */
  270.                 struct CNode *cbuf, *cbufp, *curnode;
  271.  
  272.                 /* depth2 is a short time used to count number of lines */
  273.                 for(i = depth2 = 0; i < fib->fib_Size; ++i)
  274.                 {
  275.                   if(mem[i] == '\n')
  276.                     ++depth2;
  277.                 }
  278.                 depth2 += 5; /* security */
  279. #ifdef DEBUG
  280.   Printf("Number of allocated blocks: %ld\n", depth2);
  281. #endif
  282.                 if((cbuf = AllocVec(depth2*(sizeof(struct CNode))+sizeof(struct MyOutBuf), MEMF_CLEAR)))
  283.                 {
  284.                   struct MyOutBuf *outbuf = (struct MyOutBuf *) (cbuf+depth2);
  285.  
  286.                   outbuf->FileHandle = Output();
  287.                   outbuf->DOSBase = DOSBase;
  288.                   outbuf->SysBase = SysBase;
  289.                   if(!args.outfile || (outbuf->FileHandle = Open(args.outfile, MODE_NEWFILE)))
  290.                   {
  291.                     depth2 = i = 0;
  292.  
  293.                     while(i < fib->fib_Size) /* skip the start texts */
  294.                     {
  295.                       if(!mystrncmp("Virus-Checking", mem+i, 14))
  296.                       {
  297.                         while(mem[i++] != '\n')
  298.                          ;
  299.                       }
  300.                       else if(!mystrncmp("The xvs.library", mem+i, 15))
  301.                       {
  302.                         while(mem[i++] != '\n')
  303.                           ;
  304.                       }
  305.                       else if(!mystrncmp("Your system memory", mem+i, 18))
  306.                       {
  307.                         while(mem[i++] != '\n')
  308.                           ;
  309.                       }
  310.                       else
  311.                         break;
  312.                     }
  313.  
  314.                     cbufp = cbuf;
  315.  
  316.                     /* the master header, no bytes */
  317.                     curnode = cbufp++;
  318.                     cbufp->Head = curnode;
  319.                     curnode->Sub = cbufp;
  320.  
  321.                     /* the first line */
  322.                     curnode = cbufp++;
  323.                     curnode->BufferPos = i;
  324.                     while(mem[i++] != '\n')
  325.                       ;
  326.  
  327.                     while(i < fib->fib_Size && mem[i] != '\n'
  328.                     && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  329.                     /* this is either the empty line or file end */
  330.                     {
  331.                       ULONG d, i2 = 0;
  332.  
  333.                       if(mem[i] != ' ') /* if ' ' attach a type line to current type */
  334.                       {
  335.                         if(args.crc)
  336.                         {
  337.                           for(i2 = 0; i2 < 9 && mem[i+i2] != '\n'; ++i2)
  338.                             ;
  339.                           if(i2 != 9) i2 = 0;
  340.                         }
  341.  
  342.                         if(!curnode->Size)
  343.                           curnode->Size = i-curnode->BufferPos;
  344.                         for(d = 0; mem[i+i2+d] == '*'; ++d)
  345.                           ;
  346.                         if(d > depth1) /* a subtype */
  347.                         {
  348.                           cbufp->Head      = curnode;
  349.                           cbufp->BufferPos = i;
  350.                           cbufp->Flags     = args.crc;
  351.                           curnode->Sub     = cbufp;
  352.                           curnode = cbufp++;
  353.                           ++depth1;
  354.                         }
  355.                         else if(d == depth1) /* equal or subtype 2 */
  356.                         {
  357.                           if(!mystrncmp("--infotext", mem+i+i2+d, 10))
  358.                           {
  359.                             if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
  360.                             {
  361.                               cbufp->Prev      = curnode;
  362.                               cbufp->Head      = curnode->Head;
  363.                               cbufp->BufferPos = i;
  364.                               cbufp->Flags     = FLAG_INFOTEXT|args.crc;
  365.                               curnode->Next    = cbufp;
  366.                               curnode = cbufp++;
  367.                             }
  368.                             else
  369.                             {
  370.                               cbufp->Head      = curnode;
  371.                               cbufp->BufferPos = i;
  372.                               cbufp->Flags     = FLAG_INFOTEXT|args.crc;
  373.                               if(curnode->Sub)
  374.                               {
  375.                                 for(curnode = curnode->Sub; curnode->Next; curnode = curnode->Next)
  376.                                   ;
  377.                                 curnode->Next = cbufp;
  378.                                 cbufp->Prev = curnode;
  379.                               }
  380.                               else
  381.                                 curnode->Sub = cbufp;
  382.                               curnode = cbufp++;
  383.                               ++depth2;
  384.                             }
  385.                           }
  386.                           else if(!mystrncmp("-disk image", mem+i+i2+d, 11))
  387.                           {
  388.                             if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
  389.                             {
  390.                               cbufp->Prev      = curnode;
  391.                               cbufp->Head      = curnode->Head;
  392.                               cbufp->BufferPos = i;
  393.                               cbufp->Flags     = FLAG_DISKIMAGE|args.crc;
  394.                               curnode->Next    = cbufp;
  395.                               curnode = cbufp++;
  396.                             }
  397.                             else
  398.                             {
  399.                               cbufp->Head      = curnode;
  400.                               cbufp->BufferPos = i;
  401.                               cbufp->Flags     = FLAG_DISKIMAGE|args.crc;
  402.                               if(curnode->Sub)
  403.                               {
  404.                                 for(curnode = curnode->Sub; curnode->Next; curnode = curnode->Next)
  405.                                   ;
  406.                                 curnode->Next = cbufp;
  407.                                 cbufp->Prev = curnode;
  408.                               }
  409.                               else
  410.                                 curnode->Sub = cbufp;
  411.                               curnode = cbufp++;
  412.                               ++depth2;
  413.                             }
  414.                           }
  415.                           else /* new equal type */
  416.                           {
  417.                             if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
  418.                             {
  419.                               --depth2;
  420.                               curnode = curnode->Head;
  421.                               SortSubTree(curnode, mem, SysBase);
  422.                             }
  423.                             cbufp->Prev      = curnode;
  424.                             cbufp->Head      = curnode->Head;
  425.                             cbufp->BufferPos = i;
  426.                             cbufp->Flags     = args.crc;
  427.                             curnode->Next    = cbufp;
  428.                             curnode = cbufp++;
  429.                           }
  430.                         }
  431.                         else /* leave that level depth1-d times, take care for depth2 and sizes */
  432.                         {
  433.                           /* set sizes! */
  434.                           while(depth1 > d || curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
  435.                           {
  436.                             if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
  437.                               --depth2;
  438.                             else
  439.                               --depth1;
  440.                             curnode = curnode->Head;
  441.                             SortSubTree(curnode, mem, SysBase);
  442.                           }
  443.                           continue; /* parse this again */
  444.                         }
  445.                       }
  446.                       else
  447.                       {
  448.                         for(d = 0; mem[i+d] == ' '; ++d)
  449.                           ;
  450.                         if(args.crc) d -= 9;
  451.                         if(d <= depth1 || curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
  452.                         {
  453.                           if(!curnode->Size)
  454.                             curnode->Size = i-curnode->BufferPos;
  455.                           while(depth1 >= d)
  456.                           {
  457.                             if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
  458.                               --depth2;
  459.                             else
  460.                               --depth1;
  461.                             curnode = curnode->Head;
  462.                             SortSubTree(curnode, mem, SysBase);
  463.                           }
  464.                           cbufp->Prev      = curnode;
  465.                           cbufp->Head      = curnode->Head;
  466.                           cbufp->BufferPos = i;
  467.                           cbufp->Flags     = FLAG_FILESYSTEM|args.crc;
  468.                           curnode->Next    = cbufp;
  469.                           curnode = cbufp++;
  470.                         }
  471.  
  472.                       }
  473.                       while(mem[i++] != '\n')
  474.                         ;
  475. #ifdef DEBUG
  476.   {
  477.     int size;
  478.  
  479.     Printf("CurNode: %10ld %08lx P:%08lx H:%08lx Pos:$%08lx %ld %ld %ld",
  480.     curnode-cbuf, curnode, curnode->Prev, curnode->Head, curnode->BufferPos,
  481.     d, depth1, depth2);
  482.     for(size = 0; mem[curnode->BufferPos+size] != '\n'; ++size)
  483.       FPutC(Output(), mem[curnode->BufferPos+size]);
  484.     FPutC(Output(), '\n');
  485.     Flush(Output());
  486.   }
  487. #endif
  488.                     }
  489.                     if(i > fib->fib_Size)
  490.                       i = fib->fib_Size;
  491.                     if(!curnode->Size)
  492.                       curnode->Size = i-curnode->BufferPos;
  493.                     while(curnode->Head)
  494.                     {
  495.                       curnode = curnode->Head;
  496.                       SortSubTree(curnode, mem, SysBase);
  497.                     }
  498.  
  499.                     /* curnode now represents a complete tree, where each entry starts
  500.                        with a filename (or disk image, infotext) and may have additional
  501.                        texts after the first line. For a file information tree only use
  502.                        first line (except for filesystem which has no name)!
  503.                      */
  504.                     if(curnode->BufferPos && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  505.                       MyOutput(mem, curnode->BufferPos, outbuf);
  506.                     cbufp = cbuf->Sub;
  507.                     while(cbufp && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  508.                     {
  509.                       if(args.oldfix)
  510.                       {
  511.                         STRPTR buf, bufend, beg;
  512.  
  513.                         buf = mem+cbufp->BufferPos;
  514.                         bufend = buf+cbufp->Size;
  515.                         while(buf < bufend)
  516.                         {
  517.                           beg = buf;
  518.                           if(*buf == ' ')
  519.                           {
  520.                             const struct MyReplace *mr = ReplaceField;
  521.  
  522.                             while(*buf == ' ')
  523.                               ++buf;
  524.                             MyOutput(beg, buf-beg, outbuf);
  525.                             beg = buf;
  526.  
  527.                             while(mr->OldSize && mystrncmp(buf,
  528.                             ((STRPTR)StringField)+mr->Offset, mr->OldSize))
  529.                               ++mr;
  530.                             if(mr->OldSize)
  531.                             {
  532.                               MyOutput(((STRPTR)StringField)+mr->OldSize+mr->Offset,
  533.                               mr->NewSize, outbuf);
  534.                               buf += mr->OldSize;
  535.                               continue;
  536.                             }
  537.                           }
  538.                           while(buf < bufend && *(buf++) != '\n')
  539.                             ;
  540.                           MyOutput(beg, buf-beg, outbuf);
  541.                         }
  542.                       }
  543.                       else
  544.                         MyOutput(mem+cbufp->BufferPos, cbufp->Size, outbuf);
  545.  
  546.                       if(cbufp->Sub) cbufp = cbufp->Sub;
  547.                       else if(cbufp->Next) cbufp = cbufp->Next;
  548.                       else
  549.                       {
  550.                         cbufp = cbufp->Head;
  551.                         while(cbufp && !cbufp->Next)
  552.                           cbufp = cbufp->Head;
  553.                         if(cbufp) cbufp = cbufp->Next;
  554.                       }
  555.                     }
  556.                     if(i < fib->fib_Size && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  557.                       MyOutput(mem+i, fib->fib_Size-i, outbuf);
  558.                     if(outbuf->CurSize)
  559.                       Write(outbuf->FileHandle, outbuf->Buffer, outbuf->CurSize); /* Flush buffer */
  560.                     if(args.outfile)
  561.                       Close(outbuf->FileHandle);
  562.                   }
  563.                   FreeVec(cbuf);
  564.                 }
  565.               }
  566.               FreeMem(mem, fib->fib_Size+1);
  567.             }
  568.           }
  569.           FreeDosObject(DOS_FIB, fib);
  570.         }
  571.         if(fh)
  572.           Close(fh);
  573.       }
  574.  
  575.       FreeArgs(rda);
  576.     }
  577.  
  578.     CloseLibrary((struct Library *) DOSBase);
  579.   }
  580.   return 0;
  581. }
  582.  
  583. #define DOSBase outbuf->DOSBase
  584. #define SysBase outbuf->SysBase
  585. static void MyOutput(STRPTR mem, ULONG size, struct MyOutBuf *outbuf)
  586. {
  587.   ULONG maxs;
  588.   do
  589.   {
  590.     maxs = OUTBUFSIZE - outbuf->CurSize;
  591.     if(maxs > size)
  592.       maxs = size;
  593.     CopyMem(mem, outbuf->Buffer+outbuf->CurSize, maxs);
  594.     outbuf->CurSize += maxs;
  595.     mem += maxs;
  596.     size -= maxs;
  597.     if(outbuf->CurSize == OUTBUFSIZE)
  598.     {
  599.       Write(outbuf->FileHandle, outbuf->Buffer, OUTBUFSIZE);
  600.       outbuf->CurSize = 0;
  601.     }
  602.   } while(size);
  603. }
  604. #undef SysBase
  605. #undef DOSBase
  606.  
  607. static LONG mystrncmp(STRPTR a, STRPTR b, ULONG s)
  608. {
  609.   while(s && *a && *a == *b)
  610.   {
  611.     ++a; ++b; --s;
  612.   }
  613.   return s ? (*a - *b) : 0;
  614. }
  615.  
  616. #define mytolower(a) ((a >= 'A' && a <= 'Z') || (a >= 0xC0 && a <= 0xDE) ? a+32 : a)
  617.  
  618. /* Sorts case insensitive, when equal the case is used for sorting,
  619.    if still equal the order is undefined! */
  620. static LONG MyNodeComp(struct CNode *list, struct CNode *new, STRPTR mem)
  621. {
  622.   STRPTR l, n;
  623.   LONG d, e;
  624.  
  625.   if(list->Flags & (FLAG_UNUSED|FLAG_DISKIMAGE|FLAG_INFOTEXT|FLAG_FILESYSTEM)) /* always greater */
  626.     return 1000;
  627.  
  628.   l = mem+list->BufferPos;
  629.   n = mem+new->BufferPos;
  630.   if(new->Flags & FLAG_CRC)
  631.   {
  632.     for(d = 0; d < 9 && l[d] != '\n' && n[d] != '\n'; ++d)
  633.       ;
  634.     if(d == 9)
  635.     {
  636.       l += d;
  637.       n += d;
  638.     }
  639.   }
  640.   d = 0;
  641.  
  642.   while(!(e = (mytolower(*l) - mytolower(*n))) && *l != '\n')
  643.   {
  644.     if(*l != *n && !d) /* sort by case if equal */
  645.       d = *l-*n;
  646.     ++l; ++n;
  647.   }
  648.   return (e ? e : d);
  649. }
  650.  
  651. static struct CNode *InsertFront(struct CNode *list, struct CNode *newnode)
  652. {
  653.   struct CNode *next;
  654.  
  655.   if((next = newnode->Next))
  656.     next->Prev = 0;
  657.  
  658.   newnode->Next = list;
  659.   if((newnode->Prev = list->Prev))
  660.     newnode->Prev->Next = newnode;
  661.   list->Prev = newnode;
  662.  
  663.   return next;
  664. }
  665.  
  666. static void SortSubTree(struct CNode *curnode, STRPTR mem, struct ExecBase *SysBase)
  667. {
  668.   struct CNode *oldlist, *list, dummylast;
  669.   /* list = list of new nodes */
  670.   /* oldlist = list of old nodes */
  671.  
  672.   if(!(oldlist = curnode->Sub))
  673.     return;
  674.   dummylast.Prev = dummylast.Next = 0;
  675.   dummylast.Flags = FLAG_UNUSED;
  676.   list = &dummylast; /* the dummy entry is to make work easier and faster */
  677.  
  678.   while((oldlist = InsertFront(list, oldlist)) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  679.   {
  680.     if(oldlist->Flags & (FLAG_DISKIMAGE|FLAG_INFOTEXT|FLAG_FILESYSTEM))
  681.       list = &dummylast; /* insert at end - in correct (unsorted) order */
  682.     else if(MyNodeComp(list, oldlist, mem) <= 0)
  683.     {
  684.       list = list->Next;
  685.       while(MyNodeComp(list, oldlist, mem) <= 0 && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  686.         list = list->Next;
  687.     }
  688.     else /* insert before this */
  689.     {
  690.       while(list->Prev && (MyNodeComp(list->Prev, oldlist, mem) > 0) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  691.         list = list->Prev;
  692.     }
  693.   }
  694.   while(list->Prev)
  695.     list = list->Prev;
  696.  
  697.   dummylast.Prev->Next = 0; /* remove last entry */
  698.   curnode->Sub = list; /* the start of list */
  699. }
  700. #endif /* MAKEREPLACEFIELD */
  701.